package util
{
	import mx.controls.Alert;
	import mx.rpc.AsyncToken;
	import mx.rpc.Responder;
	import mx.rpc.events.FaultEvent;
	import mx.rpc.remoting.RemoteObject;
	
	import weborb.data.DatabaseAsyncToken;
	
	/**
	 * Singleton helper class to call Remote Services.
	 * 
	 * @TODO : description of usage 
	 * @author jbaeck
	 * 
	 */
	public class RemoteServiceInvoker
	{
		private static var m_instance:RemoteServiceInvoker = new RemoteServiceInvoker();
		
		private var destination:String = "GenericDestination";
		
		/**
		 * This is a singleton class so this Constructor will throw an Error when you
		 * try. 
		 * 
		 */
		public function RemoteServiceInvoker()
		{
			if(m_instance)
			{
				throw Error("Singleton Class use method : getInstance() - you ar not allowed to call the constructor !!!!");
			}
		}
		
		/**
		 * Returns the singleton instance of this class. 
		 * @return The Singleton of this class
		 * 
		 */
		public static function getInstance():RemoteServiceInvoker
		{
			return m_instance;
		}
		
		/**
		 * Returns an RemoteObject with the given serviceName. 
		 * The Destination of the RemoteObject is defined by the var destination. 
		 * 
		 * @param serviceName The RemoteService Name
		 * @return RemoteObject for the given serviceName
		 * 
		 */
		protected function createRemoteObject(serviceName:String):RemoteObject
		{
			var ro:RemoteObject = new RemoteObject(destination);
			ro.source = serviceName;
			return ro;
		}
		
		/**
		 * Calls a RemoteService and users WebOrb to handle ActiveRecords when possible.
		 * 
		 * Uses DataBaseAsyncToken to call the RemoteService. The passed in returnObject will be the concrete type of the
		 * response. When no resultHandler is passed in an Alert with the Result will be displayed. When no faultHandler is passed
		 * in an Alert with the fault if any will be displayed.
		 * 
		 * @param returnObject The concrete class which will be returned. 
		 * @param serviceName The RemoteService to call
		 * @param functionName The function/method of the RemoteService to call
		 * @param resultHandler The function which will be called when a Result was received / when ommited an Alert will be displayed
		 * @param faultHandler The function which will be called when an Fault occured / when ommited an Alert will be displayed
		 * @param args The parameters for the RemoteService.Function
		 * 
		 */
		public function executeWDM(returnObject:*,serviceName:String,functionName:String,resultHandler:Function = null,faultHandler:Function = null,... args):void
		{
			var ro:RemoteObject = createRemoteObject(serviceName);
			var tok:AsyncToken= ro[functionName].send.apply(null,args);	
			var db:DatabaseAsyncToken = new DatabaseAsyncToken(tok,null,returnObject);
			db.addResponder(new Responder(resultHandler == null ? onResult : resultHandler,faultHandler == null ? onFault : faultHandler));	
		}
		
		
		public function execute(serviceName:String,functionName:String,resultHandler:Function = null,faultHandler:Function=null,... args):void
		{
			var ro:RemoteObject = createRemoteObject(serviceName);
			var tok:AsyncToken= ro[functionName].send.apply(null,args);	
			
			tok.addResponder(new Responder(resultHandler == null ? onResult : resultHandler,faultHandler == null ? onFault : faultHandler));
						
		}
		
		/**
		 * The default FaultHandler of the RemoteCall.  
		 * @param e The FaultEvent
		 * 
		 */
		public function onFault(e:FaultEvent):void
		{
			Alert.show("Caught Exception :"+e,"Generic Fault Handler in RemoteServiceInvoker");
		}
		
		/**
		 * The default ResultHandler of the RemoteCall. 
		 * @param e The Result of the remote call.
		 * 
		 */
		public function onResult(e:*):void
		{
			Alert.show("Got Result : "+e,"Generic Result Handler in RemoteServiceInvoker");	
		}
		
	}
}